package code {

import code.vo.Category;
import code.vo.NeededTopic;
import code.vo.OfferedTopic;
import code.vo.Topic;
import code.vo.User;

import com.adobe.cairngorm.model.IModelLocator;

import logging.Logger;

import mx.collections.ArrayCollection;
import mx.collections.XMLListCollection;
import mx.controls.AdvancedDataGrid;
	

[Bindable]
public class Model implements IModelLocator {

	private static const LOG: Logger = Logger.getLogger("code.Model");
	
	public var loginUsername: String;
	public var loginPassword: String;
	public var loginEmail: String;
	
	public var loginRemember: Boolean;
	public var isLoginBlocked: Boolean = false;
	
	
	public var currentUser: User;
	
	public var offeredCategories: ArrayCollection = new ArrayCollection();
	
	public var neededCategories: ArrayCollection = new ArrayCollection();

	public var currentCategory: Category;	
	
	public var neededTopicsAdvancedDataGridHack: AdvancedDataGrid;
	public var offeredTopicsAdvancedDataGridHack: AdvancedDataGrid;
	
	public var maxVoteCount: uint;
	
	private var _currentTopic: Topic;
	public function get currentTopic(): Topic {
		return _currentTopic;
	}
	public function set currentTopic(value: Topic): void {
		menuitemsXml.menuitem[1].menuitem[0].@enabled = (value != null);
		
		_currentTopic = value;
	}
	
	
	private var menuitemsXml: XML = 
                <menuitems>
		            <menuitem label="Application" position="top">
		                 <menuitem label="Add Topic ..." cmd="CMD_ADD_TOPIC" />
		                 <menuitem type="separator" />
		                 <menuitem label="Logout" cmd="CMD_LOGOUT" />
		            </menuitem>
		            <menuitem label="View" position="top">
		                <menuitem label="Topic Details ..." cmd="CMD_TOPIC_DETAILS" enabled="false" />
		                 <menuitem type="separator" />
		                <menuitem label="Expand All" cmd="CMD_EXPAND_ALL"/>
		                <menuitem label="Collapse All" cmd="CMD_COLLAPSE_ALL"/>
		            </menuitem>
                </menuitems>
	public var menubarData: XMLListCollection = new XMLListCollection(menuitemsXml.menuitem);

	/*
    <menuitem label="View" position="top">
        <menuitem label="Expand All" type="radio" groupName="one"/>
        <menuitem label="SubMenuItem D-2" type="radio" groupName="one" selected="true"/>
        <menuitem label="SubMenuItem D-3" type="radio" groupName="one"/>
    </menuitem>            
	<menuitem label="SubMenuItem A-1" enabled="False"/>
	<menuitem label="MenuItem B" type="check" selected="true"/>
    <menuitem label="MenuItem C" type="check" selected="false"/>
	*/

	private static var INSTANCE: Model; 
	public function Model(singletonEnforcer: SingletonEnforcer) { }
	public static function get instance(): Model {
		if(INSTANCE == null) { INSTANCE = new Model(new SingletonEnforcer()); }
		return INSTANCE;
	}
	// TODO duplicate code for categories!
	private var neededCategoriesMapping: Array = null;
	private function initializeNeededCategoriesMapping(): void {
		if(this.neededCategories == null) {
			throw new Error("Illegal state: neededCategories == null");
		}
		if(this.neededCategoriesMapping != null) {
			throw new Error("Illegal state: neededCategoriesMapping != null");
		}
		
		this.neededCategoriesMapping = new Array();
		for each(var cat: Category in this.neededCategories) {
			this.neededCategoriesMapping[cat.categoryId] = cat;
		}
	}
	
	private var offeredCategoriesMapping: Array = null;
	private function initializeOfferedCategoriesMapping(): void {
		if(this.offeredCategories == null) {
			throw new Error("Illegal state: offeredCategories == null");
		}
		if(this.offeredCategoriesMapping != null) {
			throw new Error("Illegal state: offeredCategoriesMapping != null");
		}
		
		this.offeredCategoriesMapping = new Array();
		for each(var cat: Category in this.offeredCategories) {
			this.offeredCategoriesMapping[cat.categoryId] = cat;
		}
	}
	
	public function addNeededTopicByCategory(topic: NeededTopic): void {
		if(this.neededCategoriesMapping == null) {
			this.initializeNeededCategoriesMapping();
		}
		this.checkMaxVoteCount(topic);
		
		const c: Category = this.neededCategoriesMapping[topic.categoryId] as Category;
		c.topics.addItem(topic);
	}
	public function addOfferedTopicByCategory(topic: OfferedTopic): void {
		if(this.offeredCategoriesMapping == null) {
			this.initializeOfferedCategoriesMapping();
		}
		this.checkMaxVoteCount(topic);
		
		const c: Category = this.offeredCategoriesMapping[topic.categoryId] as Category;
		c.topics.addItem(topic);
	}
	
	private function checkMaxVoteCount(topic: Topic): void {
		if(topic.voteCnt > this.maxVoteCount) {
			LOG.finest("checkMaxVoteCount() setting maxVoteCount to: " + topic.voteCnt);
			this.maxVoteCount = topic.voteCnt;
		}
	}
	// somehow a hack
	public function recheckMaxVoteCount(): void {
		var x: uint = 0;
		for each(var ncategory: Category in this.neededCategories) {
			for each(var ntopic: NeededTopic in ncategory.topics) {
				if(ntopic.voteCnt > x) {
					x = ntopic.voteCnt;
				}
			}
		}
		for each(var ocategory: Category in this.offeredCategories) {
			for each(var otopic: OfferedTopic in ocategory.topics) {
				if(otopic.voteCnt > x) {
					x = otopic.voteCnt;
				}
			}
		}
		LOG.finer("recheckMaxVoteCount() setting maxVoteCount from: " +  this.maxVoteCount + " to: " + x);
		this.maxVoteCount = x;
	}
	
	public function getOfferedCategoryById(id: int): Category {
		const result: Category = this.offeredCategoriesMapping[id];
		if(result == null) {
			throw new Error("Invalid category id: " + id);
		}
		return result;
	}
	public function getNeededCategoryById(id: int): Category {
		const result: Category = this.neededCategoriesMapping[id];
		if(result == null) {
			throw new Error("Invalid category id: " + id);
		}
		return result;
	}
	
	
	
	private var _usersMapping: Array = null;
	public function setUsers(users: ArrayCollection): void {
		/* TODO register request needs to rewrite this stuff ... if(_usersMapping != null) {
			throw new Error("Users mapping already set!");
		}*/
		_usersMapping = new Array();
		for each(var u: User in users) {
			_usersMapping[u.userId] = u;
		}
	}
	
	public function getUserById(id: int): User {
		const result: User = _usersMapping[id];
		if(result == null) {
			throw new Error("Invalid user id: " + id);
		}
		return result;
	}
}
}

class SingletonEnforcer { }
